using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace Test {
	class Lnk {

		static void MainX() {

			DirectoryInfo dinf=new DirectoryInfo(@"\\pon-ipis01\StartMenuV2\Programs\Warehouse\");

			FileInfo[] arr=GetFiles(dinf,"*.lnk");
			foreach(FileInfo fin in arr)
			{

				string str=Lnk.ResolveShortcut(fin.FullName);
				Console.WriteLine(fin.FullName+" -> "+str);
			}

		}

		static FileInfo[] GetFiles(DirectoryInfo dir,string pattern) {
			List<FileInfo> lst=new List<FileInfo>();
			lst.AddRange(dir.GetFiles(pattern));

			foreach(DirectoryInfo di in dir.GetDirectories())
			{
				lst.AddRange(GetFiles(di,pattern));
			}
			return lst.ToArray();
		}

		static void MainC() {




			string link="link.lnk";
			//IWshRuntimeLibrary - references com+ windows script host obj model
			//WshShellClass wsh=new WshShellClass();
			//IWshRuntimeLibrary.IWshShortcut shortcut=wsh.CreateShortcut(link) as IWshRuntimeLibrary.IWshShortcut;
			//shortcut.Arguments="c:\\app\\settings1.xml";
			//shortcut.TargetPath="c:\\app\\myftp.exe";
			//// not sure about what this is for
			//shortcut.WindowStyle=1;
			//shortcut.Description="my shortcut description";
			//shortcut.WorkingDirectory="c:\\app";
			//shortcut.IconLocation="specify icon location";
			//shortcut.Save();
			//IWshRuntimeLibrary.IWshShell shell=new IWshRuntimeLibrary.WshShell();
			//IWshRuntimeLibrary.IWshShortcut sc=(IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(link);
			//Console.WriteLine(sc.TargetPath);
			string str=Lnk.ResolveShortcut(link);
		}
		[DllImport("shfolder.dll",CharSet=CharSet.Auto)]
		internal static extern int SHGetFolderPath(IntPtr hwndOwner,int nFolder,IntPtr hToken,int dwFlags,StringBuilder lpszPath);
		[Flags()]
		enum SLGP_FLAGS {
			/// <summary>Retrieves the standard short (8.3 format) file name</summary>
			SLGP_SHORTPATH=0x1,
			/// <summary>Retrieves the Universal Naming Convention (UNC) path name of the file</summary>
			SLGP_UNCPRIORITY=0x2,
			/// <summary>Retrieves the raw path name. A raw path is something that might not exist and may include environment variables that need to be expanded</summary>
			SLGP_RAWPATH=0x4
		}
		[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]
		struct WIN32_FIND_DATAW {
			public uint dwFileAttributes;
			public long ftCreationTime;
			public long ftLastAccessTime;
			public long ftLastWriteTime;
			public uint nFileSizeHigh;
			public uint nFileSizeLow;
			public uint dwReserved0;
			public uint dwReserved1;
			[MarshalAs(UnmanagedType.ByValTStr,SizeConst=260)]
			public string cFileName;
			[MarshalAs(UnmanagedType.ByValTStr,SizeConst=14)]
			public string cAlternateFileName;
		}
		[Flags()]
		enum SLR_FLAGS {
			/// <summary>
			/// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set,
			/// the high-order word of fFlags can be set to a time-out value that specifies the
			/// maximum amount of time to be spent resolving the link. The function returns if the
			/// link cannot be resolved within the time-out duration. If the high-order word is set
			/// to zero, the time-out duration will be set to the default value of 3,000 milliseconds
			/// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out
			/// duration, in milliseconds.
			/// </summary>
			SLR_NO_UI=0x1,
			/// <summary>Obsolete and no longer used</summary>
			SLR_ANY_MATCH=0x2,
			/// <summary>If the link object has changed, update its path and list of identifiers.
			/// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine
			/// whether or not the link object has changed.</summary>
			SLR_UPDATE=0x4,
			/// <summary>Do not update the link information</summary>
			SLR_NOUPDATE=0x8,
			/// <summary>Do not execute the search heuristics</summary>
			SLR_NOSEARCH=0x10,
			/// <summary>Do not use distributed link tracking</summary>
			SLR_NOTRACK=0x20,
			/// <summary>Disable distributed link tracking. By default, distributed link tracking tracks
			/// removable media across multiple devices based on the volume name. It also uses the
			/// Universal Naming Convention (UNC) path to track remote file systems whose drive letter
			/// has changed. Setting SLR_NOLINKINFO disables both types of tracking.</summary>
			SLR_NOLINKINFO=0x40,
			/// <summary>Call the Microsoft Windows Installer</summary>
			SLR_INVOKE_MSI=0x80
		}
		/// <summary>The IShellLink interface allows Shell links to be created, modified, and resolved</summary>
		[ComImport(),InterfaceType(ComInterfaceType.InterfaceIsIUnknown),Guid("000214F9-0000-0000-C000-000000000046")]
		interface IShellLinkW {
			/// <summary>Retrieves the path and file name of a Shell link object</summary>
			void GetPath([Out(),MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,int cchMaxPath,out WIN32_FIND_DATAW pfd,SLGP_FLAGS fFlags);
			/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
			void GetIDList(out IntPtr ppidl);
			/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
			void SetIDList(IntPtr pidl);
			/// <summary>Retrieves the description string for a Shell link object</summary>
			void GetDescription([Out(),MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,int cchMaxName);
			/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
			void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
			/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
			void GetWorkingDirectory([Out(),MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,int cchMaxPath);
			/// <summary>Sets the name of the working directory for a Shell link object</summary>
			void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
			/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
			void GetArguments([Out(),MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,int cchMaxPath);
			/// <summary>Sets the command-line arguments for a Shell link object</summary>
			void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
			/// <summary>Retrieves the hot key for a Shell link object</summary>
			void GetHotkey(out short pwHotkey);
			/// <summary>Sets a hot key for a Shell link object</summary>
			void SetHotkey(short wHotkey);
			/// <summary>Retrieves the show command for a Shell link object</summary>
			void GetShowCmd(out int piShowCmd);
			/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
			void SetShowCmd(int iShowCmd);
			/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
			void GetIconLocation([Out(),MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
					int cchIconPath,out int piIcon);
			/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
			void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath,int iIcon);
			/// <summary>Sets the relative path to the Shell link object</summary>
			void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,int dwReserved);
			/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
			void Resolve(IntPtr hwnd,SLR_FLAGS fFlags);
			/// <summary>Sets the path and file name of a Shell link object</summary>
			void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
		}
		[ComImport,Guid("0000010c-0000-0000-c000-000000000046"),
		InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IPersist {
			[PreserveSig]
			void GetClassID(out Guid pClassID);
		}
		[ComImport,Guid("0000010b-0000-0000-C000-000000000046"),
		InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IPersistFile:IPersist {
			new void GetClassID(out Guid pClassID);
			[PreserveSig]
			int IsDirty();
			[PreserveSig]
			void Load([In,MarshalAs(UnmanagedType.LPWStr)]string pszFileName,uint dwMode);
			[PreserveSig]
			void Save([In,MarshalAs(UnmanagedType.LPWStr)]string pszFileName,[In,MarshalAs(UnmanagedType.Bool)] bool fRemember);
			[PreserveSig]
			void SaveCompleted([In,MarshalAs(UnmanagedType.LPWStr)]string pszFileName);
			[PreserveSig]
			void GetCurFile([In,MarshalAs(UnmanagedType.LPWStr)]string ppszFileName);
		}
		const uint STGM_READ=0;
		const int MAX_PATH=260;
		// CLSID_ShellLink from ShlGuid.h 
		[ComImport(),Guid("00021401-0000-0000-C000-000000000046")]
		public class ShellLink { }
		public static string ResolveShortcut(string filename) {
			ShellLink link=new ShellLink();
			((IPersistFile)link).Load(filename,STGM_READ);
			// TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files.  
			// ((IShellLinkW)link).Resolve(hwnd, 0) 
			StringBuilder sb=new StringBuilder(MAX_PATH);
			WIN32_FIND_DATAW data=new WIN32_FIND_DATAW();
			((IShellLinkW)link).GetPath(sb,sb.Capacity,out data,0);
			return sb.ToString();
		}
	}
}
